<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <title>CANTONESE LYRICS AUTHORWARE</title>
    <style>
        html {
            height: max-content;
            margin-bottom: 50px;
        }
        .input-block {
            width: 180px;
            float: left;
            margin-right: 10px;
            margin-bottom: 30px;
            height: fit-content;
        }
        .input-block-1 {
            height: 30px;
            display: flex;
            justify-content: center;
            width: 100%;
            input {
                width: 100%;
            }
        }
        .input-block-2 {
            overflow-x: auto;
            overflow-y: scroll;
            height: 250px;
        }
    </style>
</head>

<body id="app" style="margin-bottom: 50px;">
    <h1>CANTONESE LYRICS</h1>
    <h3>By Steven Yang</h3>
    <div style="margin-top: 20px;">
        <div>Querying By Tone Number Sequence According To The Rhythm (1-4). e.g. 123432111</div>
        <div style="margin-top: 10px; display: flex; align-items: center;">
            <input type="text" v-model="toneNumbers" style="margin-right: 10px; width: 900px; font-size: 56px;">
        </div>
    </div>
    <h2>Result</h2>
    <div v-if="toneNumbersArray.length === 0">
        <ul>
            <li>No record's been found.</li>
            <li>Note that a simple formula system is available. Like ^, $, to be put at the beginning and the end, are as well as in the Regular Expression; = is used for the accurate matching by Pinyin without tone; * is designed to match the vowels, and it's put at the beginning of the text input.</li>
        </ul>
    </div>
    <div v-else>
        <div v-for="(item, index) in toneNumbersArray" class="input-block">
            <div class="input-block-1">
                <input type="text" style="width: 150px;" v-model="inputBox[index]" @focus="setFocusInputBox(index)"
                    @input="inputBoxAction(index)">
            </div>
            <div class="input-block-2">
                <ol v-if="inputBox[index] === '' || inputBox[index] === null || inputBox[index] === undefined">
                    <li v-for="(item1, index1) in tonesList[toneNumbersArray[index]]">{{ item1.simplified_char }} {{ item1.improved_complete_pron }}</li>
                </ol>
                <ol v-else>
                    <li v-for="(item1, index1) in dataBox[index]" :style="{'color': item1.color !== undefined ? item1.color : '#000'}">{{ item1.simplified_char }} {{ item1.improved_complete_pron }}</li>
                </ol>
            </div>
        </div>
    </div>
    <script type="module">
    import { createApp, ref, reactive, computed, watch, toRaw } from "/static/vue.esm-browser.prod.js";
    createApp({
        setup() {
            const Color = {
                Wrong: "#db0077",
                Accurate: "#0036b0",
                Normal: "#000"
            }
            const tonesList = reactive(new Array(1 + 4));
            tonesList[0] = false;
            tonesList[1] = {$tone_1|raw};
            tonesList[2] = {$tone_2|raw};
            tonesList[3] = {$tone_3|raw};
            tonesList[4] = {$tone_4|raw};
            const toneNumbers = ref("");
            const toneNumbersArray = computed(() => {
                return toneNumbers.value.split("").map(value => {
                    return parseInt(value);
                });
            });
            const dataBox = ref([]);
            const inputBox = ref([]);
            const focusInputBox = ref(null);
            const setFocusInputBox = function(index) {
                focusInputBox.value = index;
            }
            watch(toneNumbers, function (newVal) {
                if (dataBox.value.length < newVal.length) {
                    const tmpDataBox = [...dataBox.value];
                    dataBox.value = new Array(newVal.length);
                    for (let i = 0; i < tmpDataBox.length; i++) {
                        dataBox.value[i] = tmpDataBox[i];
                    }
                }
                if (inputBox.value.length < newVal.length) {
                    const tmpInputBox = [...inputBox.value];
                    inputBox.value = new Array(newVal.length);
                    for (let i = 0; i < tmpInputBox.length; i++) {
                        inputBox.value[i] = tmpInputBox[i];
                    }
                }
            });
            const inputBoxAction = function (index) {
                const key = toneNumbersArray.value[focusInputBox.value];
                const currentInput = inputBox.value[focusInputBox.value];
                dataBox.value[index] = toRaw(tonesList[key]).filter(dictItem => {
                    if (currentInput.endsWith("$")) {
                        const len = inputBox.value[focusInputBox.value].length;
                        return dictItem.improved_pron.endsWith(currentInput.substring(0, len - 1));
                    }
                    if (currentInput.startsWith("^")) {
                        return dictItem.improved_pron.startsWith(currentInput.substring(1));
                    }
                    if (currentInput.startsWith("*")) {
                        return dictItem.improved_pron.endsWith(currentInput.substring(1));
                    }
                    if (currentInput.startsWith("=")) {
                        return dictItem.improved_pron === currentInput.substring(1);
                    }
                    return dictItem.improved_pron.includes(currentInput) || dictItem.simplified_char.includes(currentInput);
                }).map(dictItem => {
                    if (currentInput === dictItem.improved_pron ||
                        currentInput === dictItem.simplified_char) {
                        dictItem["color"] = Color.Accurate;
                    } else if (currentInput.startsWith("=") && (currentInput.substring(1) === dictItem.improved_pron)) {
                        dictItem["color"] = Color.Accurate;
                    } else {
                        dictItem['color'] = Color.Normal;
                    }
                    return dictItem;
                });
                if (dataBox.value[index].length === 0) {
                    const theSet = new Set();
                    theSet.add(1);
                    theSet.add(2);
                    theSet.add(3);
                    theSet.add(4);
                    theSet.delete(index);
                    dataBox.value[index] = [];
                    for (const value of theSet.values()) {
                        dataBox.value[index].push(...tonesList[value]);
                    }
                    const currentInput = inputBox.value[focusInputBox.value];
                    dataBox.value[index] = dataBox.value[index].filter(dictItem => {
                        if (currentInput.endsWith("$")) {
                            const len = inputBox.value[focusInputBox.value].length;
                            return dictItem.improved_pron.endsWith(currentInput.substring(0, len - 1));
                        }
                        if (currentInput.startsWith("^")) {
                            return dictItem.improved_pron.startsWith(currentInput.substring(1));
                        }
                        if (currentInput.startsWith("*")) {
                            return dictItem.improved_pron.endsWith(currentInput.substring(1));
                        }
                        if (currentInput.startsWith("=")) {
                            return dictItem.improved_pron === currentInput.substring(1);
                        }
                        return dictItem.simplified_char.includes(currentInput);
                    }).map(dictItem => {
                        dictItem["color"] = Color.Wrong;
                        return dictItem;
                    });
                }
            }
            return { tonesList, toneNumbers, toneNumbersArray,
                     dataBox, inputBox,
                     focusInputBox, setFocusInputBox,
                     inputBoxAction };
        }
    }).mount('#app')
    </script>
</body>
</html>